package com.dark;

import com.alibaba.dubbo.config.ApplicationConfig;
import com.alibaba.dubbo.config.MonitorConfig;
import com.alibaba.dubbo.config.ReferenceConfig;
import com.alibaba.dubbo.config.RegistryConfig;
import com.alibaba.dubbo.config.utils.ReferenceConfigCache;
import com.tcl.storage.bean.FileInfo;
import com.tcl.storage.bean.UploadFileResult;
import com.tcl.storage.bean.bpc.FileBlockInfo;
import com.tcl.storage.bean.bpc.FileInfoResult;
import com.tcl.storage.bean.bpc.FileMetaDataInfo;
import com.tcl.storage.exception.StorageException;
import com.tcl.storage.rpc.IBreakpointContinuinglyService;
import com.tcl.storage.rpc.IStorageService;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;

/**
 * 上传平台测试环境不能使用。正是环境无法连接上
 * Created by tengxue on 15-10-16.
 */
public class StorageUtil {
    private static final Logger LOG = LoggerFactory.getLogger(StorageUtil.class);

    private static String token;
    private static IStorageService storageService;
    private static IBreakpointContinuinglyService bpcService;

    private static synchronized void initStorageService() {
        if (storageService == null) {
            ApplicationConfig application = new ApplicationConfig();
            application.setName("storage-client");

            MonitorConfig monitor = new MonitorConfig();
            monitor.setProtocol("registry");
            application.setMonitor(monitor);

            // 连接注册中心配置
            RegistryConfig registry = new RegistryConfig();
            registry.setProtocol("zookeeper");
            registry.setAddress("10.0.0.183");
            registry.setCheck(false);

            // cache对象
            ReferenceConfigCache cache = ReferenceConfigCache.getCache();

            // 引用远程服务
            ReferenceConfig<IStorageService> reference = new ReferenceConfig<IStorageService>();
            reference.setApplication(application);
            reference.setRegistry(registry);
            reference.setInterface(IStorageService.class);
            reference.setCheck(false);
            reference.setVersion("2.1.0");

            // 存储服务对象
            storageService = cache.get(reference);
            if (storageService == null) {
                LOG.warn("####  init storageService fail");
            }

            ReferenceConfig<IBreakpointContinuinglyService> referenceBCS =
                    new ReferenceConfig<IBreakpointContinuinglyService>();
            referenceBCS.setApplication(application);
            referenceBCS.setRegistry(registry);
            referenceBCS.setInterface(IBreakpointContinuinglyService.class);
            referenceBCS.setCheck(false);
            referenceBCS.setVersion("1.0.0");

            // 断点续传服务对象
            bpcService = cache.get(referenceBCS);
            if (bpcService == null) {
                LOG.warn("####  init breakpointContinuinglyService fail");
            }
        }
    }

    private static String getToken() {
        if (token == null) {
            token ="dc3581a9cf77fcfa0b2f429e73e19120";
        }
        return token;
    }

    private static IStorageService getStorageService() {
        if (storageService == null) {
            initStorageService();
        }
        return storageService;
    }

    private static IBreakpointContinuinglyService getBpcService() {
        if (bpcService == null) {
            initStorageService();
        }
        return bpcService;
    }

    /**
     * 文件上传接口
     *
     * @param fileName 文件名称
     * @param InputStream 输入流
     * @param check 是否要校验
     * @throws IOException
     */
    public static UploadFileResult uploadFile(String fileName, InputStream InputStream,
                                              boolean check) throws StorageException, IOException {

        byte[] fileData = IOUtils.toByteArray(InputStream);

        FileInfo fileInfo = new FileInfo(getToken(), 1, fileName, fileData);

        long t0 = System.currentTimeMillis();
        LOG.info("{}, uploadFile, fileInfo:{}", t0, fileInfo);

        UploadFileResult result = getStorageService().uploadObject(getToken(), fileInfo);
        LOG.info("{}, uploadFile, result {}", t0, result);

        if (result.getStatus() != 1) {
            LOG.warn("{}, uploadFile failed, return.", t0);
        }

        // 校验文件内容
//        if (check) {
//            String url = result.getDomain() + result.getKey();
//            if (!checkData(url, fileData)) {
//                LOG.warn("{}, unknown file right or wrong, ruturn null", t0);
//                return null;
//            }
//        }

        LOG.info("{}, uploadFile success, cost {}ms", t0, System.currentTimeMillis() - t0);
        return result;
    }

//    private static boolean checkData(String fileUrl, byte[] fileData) {
//        if (StringUtils.isEmpty(fileUrl) || fileData == null) {
//            return false;
//        }
//        try {
//            byte[] data = HttpClientUtil.getFileData(fileUrl);
//
//            if (data == null) {
//                return false;
//            } else if (data.length != fileData.length) {
//                return false;
//            }
//
//            int len = Math.min(data.length, 100);
//            for (int i = 0; i < len; i++) {
//                if (data[i] != fileData[i]) {
//                    return false;
//                }
//            }
//        } catch (Exception e) {
//            LOG.error("checkData error", e);
//            return false;
//        }
//        return true;
//    }

    /**
     * 断点续传文件接口
     *
     * @param fileName 文件名称
     * @throws IOException
     */
    public static UploadFileResult uploadFileBPC(String fileName, InputStream InputStream,
                                                 long length) throws StorageException, IOException {

        String uniqueId = UUID.randomUUID().toString();
        int consisHash = 0;

        FileMetaDataInfo metaData = new FileMetaDataInfo();
        metaData.setToken(getToken());
        metaData.setType(1);
        metaData.setFileUniqueId(uniqueId);
        metaData.setFileName(fileName);
        metaData.setContentLenth(length);

        long t0 = System.currentTimeMillis();
        LOG.info("{}, metaData: {}", t0, metaData);

        // 上传文件元数据
        FileInfoResult result = getBpcService().uploadFileMetaDataInfo(metaData);
        LOG.info("{}, upload metaData result: {}", t0, result.toJson());

        if (result.getStatus() != 1) {
            LOG.warn("{}, upload metaData failed, return.", t0);
            return null;
        }

        // 每次传1M
        int blockSize = 1048;

        byte[] blockBuff = new byte[blockSize];

        FileBlockInfo blockInfo = new FileBlockInfo();
        blockInfo.setToken(getToken());
        blockInfo.setType(1);
        blockInfo.setFileUniqueId(uniqueId);

        for (int i = 0; i < length; i += blockSize) {
            //这里为了获取块的实际长度。文件最后一个有可能会小于初始化设定的数据长度。
            int count = IOUtils.read(InputStream, blockBuff, 0, blockSize);
            if (count < blockSize) {
                //如果小于就把真实的大小赋值给数组
                blockBuff = ArrayUtils.subarray(blockBuff, 0, count);
            }
            blockInfo.setCurrentProgress(i);
            blockInfo.setBlockBuff(blockBuff);

            // 上传文件块
            result = getBpcService().uploadFileByBlock(blockInfo);
            LOG.info("{}, upload blockInfo result: {}", t0, result.toJson());

            if(result.getStatus() != 1) {
                LOG.warn("{}, upload blockInfo failed, return. progress: {}", t0, i);
                return null;
            }
        }

        // 文件已经传完
        if (result.getUploadStatus() == 1) {
            UploadFileResult ufr = new UploadFileResult();
            ufr.setStatus(1);
            ufr.setDomain(result.getDomain());
            ufr.setKey(result.getKey());

            LOG.info("{}, uploadFile success, cost {}ms", t0, System.currentTimeMillis() - t0);
            return ufr;
        }

        return null;
    }

    /**
     * 文件上传接口
     *
     * @throws IOException
     */
    protected static UploadFileResult uploadFile(File file) throws StorageException, IOException {
        FileInfo fileInfo =
                new FileInfo(token, 1, file.getName(), FileUtils.readFileToByteArray(file));

        long t0 = System.currentTimeMillis();
        LOG.info("{}, uploadFile [token:{}, fileInfo:{}]", t0, token, fileInfo);

        UploadFileResult result = getStorageService().uploadObject(token, fileInfo);

        LOG.info("{}, uploadFile success, file size {}bytes, cost {}ms", t0, file.length(),
                System.currentTimeMillis() - t0);

        return result;
    }

    /**
     * 批量文件上传接口
     */
    protected static List<UploadFileResult> uploadFiles(List<File> fileList)
            throws StorageException, IOException {
        List<FileInfo> fileInfoList = new ArrayList<FileInfo>();
        long size = 0;
        for (File file : fileList) {
            fileInfoList.add(new FileInfo(token, 1, file.getName(), FileUtils
                    .readFileToByteArray(file)));
            size += file.length();
        }

        long t0 = System.currentTimeMillis();
        LOG.info("{}, uploadFiles [token:{}, fileInfoList:{}]", t0, token, fileInfoList);

        List<UploadFileResult> results = getStorageService().uploadObject(token, fileInfoList);

        LOG.info("{}, uploadFiles success, files size {}bytes, cost {}ms", t0, size,
                System.currentTimeMillis() - t0);

        return results;
    }

    public static void main(String[] args) throws Exception{
        File testFile=new File("/home/tengxue/Pictures/test.jpg");
         long length=testFile.length();
        SimpleDateFormat sdf=new SimpleDateFormat("yyyyMMdd/HH/mm/ss/");
        String fileName=sdf.format(new Date())+"test-portal-CD";
        UploadFileResult result=StorageUtil.uploadFileBPC(fileName,new FileInputStream(testFile),length);
        System.out.println("上传文件的结果是："+result.getStatus());

    }
}
